<!DOCTYPE html>
<html dir="ltr" lang="zh">
<head>
<meta charset="utf-8"/>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<meta content='基础 # 1.并行跟并发有什么区别？ # 并行就是同一时刻，两个线程都在执行。这就要求有两个CPU去分别执行两个线程。 并发就是同一时刻，只有一个执行，但是一个时间段内，两个线程都执行了。并发的实现依赖于CPU切换线程，因为切换的时间特别短，所以基本对于用户是无感知的。 2.说说什么是进程和线程？ # 进程：进程是代码在数据集合上的一次运行活动，是系统进行资源分配和调度的基本单位。 线程：线程是进程的一个执行路径，一个进程中至少有一个线程，进程中的多个线程共享进程的资源。 3.说说线程有几种创建方式？ # Java中创建线程主要有三种方式，分别为继承Thread类、实现Runnable接口、实现Callable接口。
继承Thread类，重写run()方法，调用start()方法启动线程
public class ThreadTest { /** * 继承Thread类 */ public static class MyThread extends Thread { @Override public void run() { System.out.println("This is child thread"); } } public static void main(String[] args) { MyThread thread = new MyThread(); thread.start(); } } 实现 Runnable 接口，重写run()方法
public class RunnableTask implements Runnable { public void run() { System.out.println("Runnable!"); } public static void main(String[] args) { RunnableTask task = new RunnableTask(); new Thread(task).' name="description"/>
<meta content="#FFFFFF" name="theme-color"/>
<meta content="light dark" name="color-scheme"/><meta content="Concurrence" property="og:title"/>
<meta content='基础 # 1.并行跟并发有什么区别？ # 并行就是同一时刻，两个线程都在执行。这就要求有两个CPU去分别执行两个线程。 并发就是同一时刻，只有一个执行，但是一个时间段内，两个线程都执行了。并发的实现依赖于CPU切换线程，因为切换的时间特别短，所以基本对于用户是无感知的。 2.说说什么是进程和线程？ # 进程：进程是代码在数据集合上的一次运行活动，是系统进行资源分配和调度的基本单位。 线程：线程是进程的一个执行路径，一个进程中至少有一个线程，进程中的多个线程共享进程的资源。 3.说说线程有几种创建方式？ # Java中创建线程主要有三种方式，分别为继承Thread类、实现Runnable接口、实现Callable接口。
继承Thread类，重写run()方法，调用start()方法启动线程
public class ThreadTest { /** * 继承Thread类 */ public static class MyThread extends Thread { @Override public void run() { System.out.println("This is child thread"); } } public static void main(String[] args) { MyThread thread = new MyThread(); thread.start(); } } 实现 Runnable 接口，重写run()方法
public class RunnableTask implements Runnable { public void run() { System.out.println("Runnable!"); } public static void main(String[] args) { RunnableTask task = new RunnableTask(); new Thread(task).' property="og:description"/>
<meta content="article" property="og:type"/>
<meta content="https://helloputong.gitee.io/notes/java-%E7%9B%B8%E5%85%B3/%E5%B9%B6%E5%8F%91/" property="og:url"/><meta content="notes" property="article:section"/>
<title>Concurrence | Hello! 噗通 🍀</title>
<link href="/manifest.json" rel="manifest"/>
<link href="/favicon.png" rel="icon" type="image/x-icon"/>
<link crossorigin="anonymous" href="/book.min.a82d7e77ceb134d151c4d7e381eeb30623fbd5a524d58c584d8716ecec0205bd.css" integrity="sha256-qC1+d86xNNFRxNfjge6zBiP71aUk1YxYTYcW7OwCBb0=" rel="stylesheet"/>
<script defer="" src="/flexsearch.min.js"></script>
<script crossorigin="anonymous" defer="" integrity="sha256-+pR/j4Voa/VXQmH38FekcfPx1IEWD5WAkNOJruKNmQk=" src="/zh.search.min.fa947f8f85686bf5574261f7f057a471f3f1d481160f958090d389aee28d9909.js"></script>
<script crossorigin="anonymous" defer="" integrity="sha256-b2+Q/LjrHEnsOJg45rgB0N4ZQwuOUWkC+NdcPIvZhzk=" src="/sw.min.6f6f90fcb8eb1c49ec389838e6b801d0de19430b8e516902f8d75c3c8bd98739.js"></script>
<!--
Made with Book Theme
https://github.com/alex-shpak/hugo-book
-->
</head>
<body dir="ltr">
<input class="hidden toggle" id="menu-control" type="checkbox"/>
<input class="hidden toggle" id="toc-control" type="checkbox"/>
<main class="container flex">
<aside class="book-menu">
<div class="book-menu-content">
<nav>
<h2 class="book-brand">
<a class="flex align-center" href="/"><span>Hello! 噗通 🍀</span>
</a>
</h2>
<div class="book-search">
<input aria-label="Search" data-hotkeys="s/" id="book-search-input" maxlength="64" placeholder="Search" type="text"/>
<div class="book-search-spinner hidden"></div>
<ul id="book-search-results"></ul>
</div>
<ul>
<li class="book-section-flat">
<span>--学习笔记--👇</span>
<ul>
<li>
<input class="toggle" id="section-62161c8b7eae8ea89aee3d6f310b2312" type="checkbox"/>
<label class="flex justify-between" for="section-62161c8b7eae8ea89aee3d6f310b2312">
<a class="" role="button">Android</a>
</label>
<ul>
<li>
<a class="" href="/notes/android/mac%E9%80%9A%E8%BF%87homebrew%E5%AE%89%E8%A3%85java8/">Mac 通过 Homebrew 安装 Java8</a>
</li>
<li>
<a class="" href="/notes/android/%E6%B4%BB%E5%8A%A8%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/">活动的生命周期</a>
</li>
<li>
<a class="" href="/notes/android/%E5%B8%B8%E7%94%A8%E6%8E%A7%E4%BB%B6%E5%92%8C4%E7%A7%8D%E5%B8%83%E5%B1%80/">常用控件和4种布局</a>
</li>
<li>
<a class="" href="/notes/android/android-%E4%B8%AD%E4%BA%8B%E4%BB%B6%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93/">Android 中事件学习总结</a>
</li>
<li>
<a class="" href="/notes/android/android-%E4%B8%AD%E7%9A%84%E6%B6%88%E6%81%AF%E6%9C%BA%E5%88%B6%E5%92%8C%E5%BC%82%E6%AD%A5%E4%BB%BB%E5%8A%A1/">Android 中的消息机制和异步任务</a>
</li>
<li>
<a class="" href="/notes/android/listview%E4%B8%AD%E5%85%B3%E4%BA%8E%E6%95%B0%E6%8D%AE%E6%9B%B4%E6%96%B0%E7%9A%84%E4%B8%A4%E4%B8%AA%E9%97%AE%E9%A2%98/">List View中关于数据更新的两个问题</a>
</li>
<li>
<a class="" href="/notes/android/spinner-%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8/">Spinner 基本使用</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-d1dc8d9746f5c776e8a82499bbb2e7c6" type="checkbox"/>
<label class="flex justify-between" for="section-d1dc8d9746f5c776e8a82499bbb2e7c6">
<a class="" role="button">BMS</a>
</label>
<ul>
<li>
<a class="" href="/notes/bms/bms-%E7%9B%B8%E5%85%B3%E7%90%86%E8%AE%BA%E5%AD%A6%E4%B9%A0/">BMS 相关概念</a>
</li>
<li>
<a class="" href="/notes/bms/%E6%BC%94%E7%A4%BA%E5%8F%82%E6%95%B0%E8%A7%A3%E8%AF%BB/">功能演示</a>
</li>
<li>
<a class="" href="/notes/bms/%E5%8E%9F%E7%90%86%E5%9B%BE%E8%A7%A3%E8%AF%BB/">原理图解读</a>
</li>
<li>
<a class="" href="/notes/bms/%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/">源码解析</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-b7444509cb631180897a34f028407c2c" type="checkbox"/>
<label class="flex justify-between" for="section-b7444509cb631180897a34f028407c2c">
<a class="" role="button">设计模式</a>
</label>
<ul>
<li>
<a class="" href="/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/uml-%E5%9B%BE/">Uml 图</a>
</li>
<li>
<a class="" href="/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E8%AE%BE%E8%AE%A1%E5%8E%9F%E5%88%99/">设计原则</a>
</li>
<li>
<a class="" href="/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E5%88%9B%E5%BB%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F/">创建型模式</a>
</li>
<li>
<a class="" href="/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E7%BB%93%E6%9E%84%E5%9E%8B%E6%A8%A1%E5%BC%8F/">结构型模式</a>
</li>
<li>
<a class="" href="/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E8%A1%8C%E4%B8%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F/">行为型模式</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-4364152b7ab5995d509c0b7b811005c4" type="checkbox"/>
<label class="flex justify-between" for="section-4364152b7ab5995d509c0b7b811005c4">
<a class="" role="button">JVM</a>
</label>
<ul>
<li>
<a class="" href="/notes/jvm/%E4%BB%80%E4%B9%88%E6%98%AF-jvm/">什么是 Jvm</a>
</li>
<li>
<a class="" href="/notes/jvm/%E7%A8%8B%E5%BA%8F%E8%AE%A1%E6%95%B0%E5%99%A8/">程序计数器</a>
</li>
<li>
<a class="" href="/notes/jvm/%E8%99%9A%E6%8B%9F%E6%9C%BA%E6%A0%88/">虚拟机栈</a>
</li>
<li>
<a class="" href="/notes/jvm/%E6%9C%AC%E5%9C%B0%E6%96%B9%E6%B3%95%E6%A0%88-/">本地方法栈</a>
</li>
<li>
<a class="" href="/notes/jvm/%E5%A0%86/">堆</a>
</li>
<li>
<a class="" href="/notes/jvm/%E6%96%B9%E6%B3%95%E5%8C%BA/">方法区</a>
</li>
<li>
<a class="" href="/notes/jvm/%E7%9B%B4%E6%8E%A5%E5%86%85%E5%AD%98/">直接内存</a>
</li>
<li>
<a class="" href="/notes/jvm/%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6/">垃圾回收</a>
</li>
<li>
<a class="" href="/notes/jvm/%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E5%99%A8/">垃圾回收器</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-61661238f18c0095524962a5d1d6e676" type="checkbox"/>
<label class="flex justify-between" for="section-61661238f18c0095524962a5d1d6e676">
<a class="" role="button">Spring</a>
</label>
<ul>
<li>
<a class="" href="/notes/spring/beanfactory%E4%B8%8Eapplicationcontext/">Bean Factory与 Application Context</a>
</li>
<li>
<a class="" href="/notes/spring/nacos-%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83/">Nacos 配置中心</a>
</li>
<li>
<a class="" href="/notes/spring/open-feign-%E8%BF%9C%E7%A8%8B%E8%B0%83%E7%94%A8%E7%A4%BA%E4%BE%8B/">Open Feign 远程调用示例</a>
</li>
<li>
<a class="" href="/notes/spring/springboot-%E6%95%B4%E5%90%88-mybatis-plus/">Spring Boot 整合 My Batis Plus</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-39abd0d44427d4a54e694a2b3f22d967" type="checkbox"/>
<label class="flex justify-between" for="section-39abd0d44427d4a54e694a2b3f22d967">
<a class="" role="button">TensorFlow</a>
</label>
<ul>
<li>
<a class="" href="/notes/tensorflow/tensorflow-%E7%AC%94%E8%AE%B0%E4%B8%80/">Tensor Flow 笔记（一）</a>
</li>
<li>
<a class="" href="/notes/tensorflow/tensorflow-%E7%AC%94%E8%AE%B0%E4%BA%8C/">Tensor Flow 笔记（二）</a>
</li>
<li>
<a class="" href="/notes/tensorflow/tensorflow-%E7%AC%94%E8%AE%B0%E4%B8%89/">Tensor Flow 笔记（三）</a>
</li>
<li>
<a class="" href="/notes/tensorflow/tensorflow-%E7%AC%94%E8%AE%B0%E5%9B%9B/">Tensor Flow 笔记（四）</a>
</li>
<li>
<a class="" href="/notes/tensorflow/tensorflow-%E7%AC%94%E8%AE%B0%E4%BA%94/">Tensor Flow 笔记（五）</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-e2ca0d138d67d9d3ae55da25ac044829" type="checkbox"/>
<label class="flex justify-between" for="section-e2ca0d138d67d9d3ae55da25ac044829">
<a class="" role="button">Redis</a>
</label>
<ul>
<li>
<a class="" href="/notes/redis/nosql%E6%95%B0%E6%8D%AE%E5%BA%93%E7%AE%80%E4%BB%8B/">No Sql数据库简介</a>
</li>
<li>
<a class="" href="/notes/redis/redis-key/">Redis Key</a>
</li>
<li>
<a class="" href="/notes/redis/redis-string/">Redis String</a>
</li>
<li>
<a class="" href="/notes/redis/redis-list/">Redis List</a>
</li>
<li>
<a class="" href="/notes/redis/redis-set/">Redis Set</a>
</li>
<li>
<a class="" href="/notes/redis/redis-hash/">Redis Hash</a>
</li>
<li>
<a class="" href="/notes/redis/redis-zset/">Redis Zset</a>
</li>
<li>
<a class="" href="/notes/redis/redis-%E5%8F%91%E5%B8%83%E4%B8%8E%E8%AE%A2%E9%98%85/">Redis 发布与订阅</a>
</li>
<li>
<a class="" href="/notes/redis/redis-jedis/">Redis Jedis</a>
</li>
<li>
<a class="" href="/notes/redis/springboot-%E6%95%B4%E5%90%88-redis/">Spring Boot 整合 Redis</a>
</li>
<li>
<a class="" href="/notes/redis/redis-%E4%BA%8B%E5%8A%A1%E5%92%8C%E9%94%81%E6%9C%BA%E5%88%B6/">Redis 事务和锁机制</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-58f730a0b22fcdc7a886db614d77f88c" type="checkbox"/>
<label class="flex justify-between" for="section-58f730a0b22fcdc7a886db614d77f88c">
<a class="" role="button">代码随想录刷题</a>
</label>
<ul>
<li>
<a class="" href="/notes/leetcode/day001-%E7%AC%AC%E4%B8%80%E7%AB%A0%E6%95%B0%E7%BB%84/">Day001 第一章数组</a>
</li>
<li>
<a class="" href="/notes/leetcode/day002-%E7%AC%AC%E4%B8%80%E7%AB%A0%E6%95%B0%E7%BB%84/">Day002 第一章数组</a>
</li>
<li>
<a class="" href="/notes/leetcode/day003-%E7%AC%AC%E4%BA%8C%E7%AB%A0%E9%93%BE%E8%A1%A8/">Day003 第二章链表</a>
</li>
<li>
<a class="" href="/notes/leetcode/day004-%E7%AC%AC%E4%BA%8C%E7%AB%A0%E9%93%BE%E8%A1%A8/">Day004 第二章链表</a>
</li>
<li>
<a class="" href="/notes/leetcode/day006-%E7%AC%AC%E4%B8%89%E7%AB%A0%E5%93%88%E5%B8%8C%E8%A1%A8/">Day006 第三章哈希表</a>
</li>
<li>
<a class="" href="/notes/leetcode/day007-%E7%AC%AC%E4%B8%89%E7%AB%A0%E5%93%88%E5%B8%8C%E8%A1%A8/">Day007 第三章哈希表</a>
</li>
<li>
<a class="" href="/notes/leetcode/day008-%E7%AC%AC%E5%9B%9B%E7%AB%A0%E5%AD%97%E7%AC%A6%E4%B8%B2/">Day008 第四章字符串</a>
</li>
<li>
<a class="" href="/notes/leetcode/day009-%E7%AC%AC%E5%9B%9B%E7%AB%A0%E5%AD%97%E7%AC%A6%E4%B8%B2/">Day009 第四章字符串</a>
</li>
<li>
<a class="" href="/notes/leetcode/day010-%E7%AC%AC%E4%BA%94%E7%AB%A0%E6%A0%88%E4%B8%8E%E9%98%9F%E5%88%97/">Day010 第五章栈与队列</a>
</li>
<li>
<a class="" href="/notes/leetcode/day011-%E7%AC%AC%E4%BA%94%E7%AB%A0%E6%A0%88%E4%B8%8E%E9%98%9F%E5%88%97/">Day011 第五章栈与队列</a>
</li>
<li>
<a class="" href="/notes/leetcode/day013-%E7%AC%AC%E4%BA%94%E7%AB%A0%E6%A0%88%E4%B8%8E%E9%98%9F%E5%88%97/">Day013 第五章栈与队列</a>
</li>
<li>
<a class="" href="/notes/leetcode/day014-%E7%AC%AC%E5%85%AD%E7%AB%A0%E4%BA%8C%E5%8F%89%E6%A0%91/">Day014 第六章二叉树</a>
</li>
<li>
<a class="" href="/notes/leetcode/day015-%E7%AC%AC%E5%85%AD%E7%AB%A0%E4%BA%8C%E5%8F%89%E6%A0%91/">Day015 第六章二叉树</a>
</li>
<li>
<a class="" href="/notes/leetcode/day017-%E7%AC%AC%E5%85%AD%E7%AB%A0%E4%BA%8C%E5%8F%89%E6%A0%91/">Day017 第六章二叉树</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-4f95435d3a74007e2c985ea455bbb6e6" type="checkbox"/>
<label class="flex justify-between" for="section-4f95435d3a74007e2c985ea455bbb6e6">
<a class="" role="button">MyBatisPlus</a>
</label>
<ul>
<li>
<a class="" href="/notes/mybatisplus/%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8/">MP快速入门</a>
</li>
<li>
<a class="" href="/notes/mybatisplus/%E4%B8%80%E8%88%AC%E6%9F%A5%E8%AF%A2%E6%93%8D%E4%BD%9C/">一般查询操作</a>
</li>
<li>
<a class="" href="/notes/mybatisplus/%E5%88%86%E9%A1%B5%E6%9F%A5%E8%AF%A2/">分页查询</a>
</li>
<li>
<a class="" href="/notes/mybatisplus/%E9%80%BB%E8%BE%91%E5%88%A0%E9%99%A4/">逻辑删除</a>
</li>
<li>
<a class="" href="/notes/mybatisplus/%E6%9D%A1%E4%BB%B6%E6%9F%A5%E8%AF%A2/">条件查询</a>
</li>
<li>
<a class="" href="/notes/mybatisplus/%E5%B0%81%E8%A3%85service%E4%BD%BF%E7%94%A8/">封装service使用</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-3907b2cf55ed520ad784e24525c8baa4" type="checkbox"/>
<label class="flex justify-between" for="section-3907b2cf55ed520ad784e24525c8baa4">
<a class="" role="button">Swift</a>
</label>
<ul>
<li>
<a class="" href="/notes/swift/swiftui-%E5%B8%B8%E7%94%A8%E8%A7%86%E5%9B%BE-views/">Swift Ui 常用视图 Views</a>
</li>
<li>
<a class="" href="/notes/swift/swiftui-%E4%BF%A1%E6%81%AF%E8%A7%86%E5%9B%BE-views/">Swift Ui 信息视图 Views</a>
</li>
<li>
<a class="" href="/notes/swift/swiftui-%E5%B1%82%E7%BA%A7%E8%A7%86%E5%9B%BE-views/">Swift Ui 层级视图 Views</a>
</li>
<li>
<a class="" href="/notes/swift/swiftui-%E6%8E%A7%E5%88%B6%E8%A7%86%E5%9B%BE-views/">Swift Ui 控制视图 Views</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-0f70934a6e5284fbc93928c61dfe9c83" type="checkbox"/>
<label class="flex justify-between" for="section-0f70934a6e5284fbc93928c61dfe9c83">
<a class="" role="button">Java</a>
</label>
<ul>
<li>
<a class="" href="/notes/java/arraylist-%E6%89%A9%E5%AE%B9%E8%A7%84%E5%88%99/">Array List 扩容规则</a>
</li>
<li>
<a class="" href="/notes/java/hashmap-%E7%9B%B8%E5%85%B3%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93/">Hash Map 相关学习总结</a>
</li>
<li>
<a class="" href="/notes/java/java-%E5%8F%8D%E5%B0%84/">Java 反射</a>
</li>
</ul>
</li>
<li>
<input checked="" class="toggle" id="section-3d1ea9814960db7e996773b67773e705" type="checkbox"/>
<label class="flex justify-between" for="section-3d1ea9814960db7e996773b67773e705">
<a class="" role="button">Java八股</a>
</label>
<ul>
<li>
<a class="active" href="/notes/java-%E7%9B%B8%E5%85%B3/%E5%B9%B6%E5%8F%91/">Concurrence</a>
</li>
<li>
<a class="" href="/notes/java-%E7%9B%B8%E5%85%B3/mybatis/">MyBatis</a>
</li>
<li>
<a class="" href="/notes/java-%E7%9B%B8%E5%85%B3/mysql/">MySQL</a>
</li>
<li>
<a class="" href="/notes/java-%E7%9B%B8%E5%85%B3/jvm/">Jvm</a>
</li>
<li>
<a class="" href="/notes/java-%E7%9B%B8%E5%85%B3/redis/">Redis</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-ea55243c547fa272027885b73a74852e" type="checkbox"/>
<label class="flex justify-between" for="section-ea55243c547fa272027885b73a74852e">
<a class="" role="button">嵌入式重点总结</a>
</label>
<ul>
<li>
<a class="" href="/notes/%E5%B5%8C%E5%85%A5%E5%BC%8F%E6%80%BB%E7%BB%93/c/">C 语言相关</a>
</li>
<li>
<a class="" href="/notes/%E5%B5%8C%E5%85%A5%E5%BC%8F%E6%80%BB%E7%BB%93/%E4%B8%AD%E6%96%AD%E7%B3%BB%E7%BB%9F/">中断系统</a>
</li>
<li>
<a class="" href="/notes/%E5%B5%8C%E5%85%A5%E5%BC%8F%E6%80%BB%E7%BB%93/%E5%AE%9A%E6%97%B6%E5%99%A8/">TIM</a>
</li>
<li>
<a class="" href="/notes/%E5%B5%8C%E5%85%A5%E5%BC%8F%E6%80%BB%E7%BB%93/adc/">ADC</a>
</li>
<li>
<a class="" href="/notes/%E5%B5%8C%E5%85%A5%E5%BC%8F%E6%80%BB%E7%BB%93/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98/">嵌入式知识点串烧</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="book-section-flat">
<span>--解决方案--👇</span>
<ul>
<li>
<input class="toggle" id="section-f1d4602254471b9d0da445dd468cd456" type="checkbox"/>
<label class="flex justify-between" for="section-f1d4602254471b9d0da445dd468cd456">
<a class="" role="button">环境配置</a>
</label>
<ul>
<li>
<a class="" href="/solution/environment/apple-m%E7%B3%BB%E5%88%97%E8%8A%AF%E7%89%87%E5%AE%89%E8%A3%85-pyqt/">Apple M系列芯片安装 Pyqt</a>
</li>
<li>
<a class="" href="/solution/environment/docker-%E5%AE%89%E8%A3%85-redis-/">Docker 安装 Redis</a>
</li>
<li>
<a class="" href="/solution/environment/hugo-%E4%B8%BB%E9%A2%98-hugo-book-%E4%B8%AD%E8%8B%B1%E6%96%87%E6%90%9C%E7%B4%A2%E9%85%8D%E7%BD%AE/">Hugo 主题 Hugo Book 中英文搜索配置</a>
</li>
<li>
<a class="" href="/solution/environment/iterm2-oh-my-zsh-%E9%85%8D%E7%BD%AE/">I Term2 Oh My Zsh 配置</a>
</li>
<li>
<a class="" href="/solution/environment/m1-%E8%8A%AF%E7%89%87-docker-%E5%AE%89%E8%A3%85-mysql5.7-/">M1 芯片 Docker 安装 Mysql5.7</a>
</li>
<li>
<a class="" href="/solution/environment/mac-idea-%E5%BF%AB%E6%8D%B7%E9%94%AE%E4%BD%8D/">MAC Idea 快捷键位</a>
</li>
<li>
<a class="" href="/solution/environment/mac-%E5%90%AF%E5%8A%A8%E5%8F%B0%E8%87%AA%E5%AE%9A%E4%B9%89%E8%A1%8C%E5%88%97%E5%B8%83%E5%B1%80/">MAC 启动台自定义行列布局</a>
</li>
<li>
<a class="" href="/solution/environment/%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F/">内网穿透</a>
</li>
<li>
<a class="" href="/solution/environment/%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F%E7%9A%84%E8%87%AA%E5%90%AF%E5%8A%A8%E8%AE%BE%E7%BD%AE/">内网穿透的自启动设置</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-5a76a664ba4855b79d3c1bc77e5b08b1" type="checkbox"/>
<label class="flex justify-between" for="section-5a76a664ba4855b79d3c1bc77e5b08b1">
<a class="" role="button">杂乱问题</a>
</label>
<ul>
<li>
<a class="" href="/solution/problems/brew-%E4%B8%80%E4%BA%9B%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/">Brew 一些常用命令</a>
</li>
<li>
<a class="" href="/solution/problems/docker-%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/">Docker 常用命令</a>
</li>
<li>
<a class="" href="/solution/problems/git-github-%E7%9B%B8%E5%85%B3%E5%91%BD%E4%BB%A4%E6%95%B4%E7%90%86/">Git Git Hub 相关命令整理</a>
</li>
<li>
<a class="" href="/solution/problems/%E9%9D%A2%E8%AF%95%E9%A2%98%E6%89%AB%E7%9B%B2/">面试题扫盲</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="book-section-flat">
<span>一点业余👇</span>
<ul>
</ul>
</li>
<li class="book-section-flat">
<span>--其他记录--👇</span>
<ul>
<li>
<input class="toggle" id="section-9ef4d2063ddc9af7785b193647f22260" type="checkbox"/>
<label class="flex justify-between" for="section-9ef4d2063ddc9af7785b193647f22260">
<a class="" role="button">我和阿刁</a>
</label>
<ul>
<li>
<a class="" href="/daily/ad/%E5%85%B3%E4%BA%8E%E9%98%BF%E5%88%812022%E5%B9%B4%E7%9A%84%E7%94%9F%E6%97%A5%E7%9A%84%E5%B0%8F%E8%AE%BA%E6%96%87/">关于阿刁2022年的生日的小论文</a>
</li>
<li>
<a class="" href="/daily/ad/%E5%85%B3%E4%BA%8E%E9%98%BF%E5%88%81%E7%9A%842021%E5%B9%B4%E5%BA%A6%E6%80%BB%E7%BB%93/">关于阿刁的2021年度总结</a>
</li>
<li>
<a class="" href="/daily/ad/%E5%85%B3%E4%BA%8E%E9%98%BF%E5%88%81%E7%9A%842022%E5%B9%B4%E5%BA%A6%E6%80%BB%E7%BB%93/">关于阿刁的2022年度总结</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
<script>(function(){var e=document.querySelector("aside .book-menu-content");addEventListener("beforeunload",function(){localStorage.setItem("menu.scrollTop",e.scrollTop)}),e.scrollTop=localStorage.getItem("menu.scrollTop")})()</script>
</div>
</aside>
<div class="book-page">
<header class="book-header">
<div class="flex align-center justify-between">
<label for="menu-control">
<img alt="Menu" class="book-icon" src="/svg/menu.svg"/>
</label>
<strong>Concurrence</strong>
<label for="toc-control">
<img alt="Table of Contents" class="book-icon" src="/svg/toc.svg"/>
</label>
</div>
<aside class="hidden clearfix">
<nav id="TableOfContents">
<ul>
<li>
<ul>
<li><a href="#基础">基础</a>
<ul>
<li><a href="#1并行跟并发有什么区别">1.并行跟并发有什么区别？</a></li>
<li><a href="#2说说什么是进程和线程">2.说说什么是进程和线程？</a></li>
<li><a href="#3说说线程有几种创建方式">3.说说线程有几种创建方式？</a></li>
<li><a href="#4为什么调用start方法时会执行run方法那怎么不直接调用run方法">4.为什么调用start()方法时会执行run()方法，那怎么不直接调用run()方法？</a></li>
<li><a href="#5线程有哪些常用的调度方法">5.线程有哪些常用的调度方法？</a></li>
<li><a href="#6线程有几种状态">6.线程有几种状态？</a></li>
<li><a href="#7什么是线程上下文切换">7.什么是线程上下文切换？</a></li>
<li><a href="#8守护线程了解吗">8.守护线程了解吗？</a></li>
<li><a href="#9线程间有哪些通信方式">9.线程间有哪些通信方式？</a></li>
</ul>
</li>
<li><a href="#threadlocal">ThreadLocal</a>
<ul>
<li><a href="#10threadlocal是什么">10.ThreadLocal是什么？</a></li>
<li><a href="#11threadlocal怎么实现的呢">11.ThreadLocal怎么实现的呢？</a></li>
<li><a href="#12threadlocal-内存泄露是怎么回事">12.ThreadLocal 内存泄露是怎么回事？</a></li>
<li><a href="#13怎么解决内存泄漏问题呢">13.怎么解决内存泄漏问题呢？</a></li>
<li><a href="#14threadlocalmap的结构了解吗">14.ThreadLocalMap的结构了解吗？</a></li>
<li><a href="#15threadlocalmap怎么解决hash冲突的">15.ThreadLocalMap怎么解决Hash冲突的？</a></li>
<li><a href="#16threadlocalmap扩容机制了解吗">16.ThreadLocalMap扩容机制了解吗？</a></li>
<li><a href="#17父子线程怎么共享数据">17.父子线程怎么共享数据？</a></li>
</ul>
</li>
<li><a href="#java内存模型">Java内存模型</a>
<ul>
<li><a href="#18说一下你对java内存模型jmm的理解">18.说一下你对Java内存模型（JMM）的理解？</a></li>
<li><a href="#19说说你对原子性可见性有序性的理解">19.说说你对原子性、可见性、有序性的理解？</a></li>
<li><a href="#20原子性可见性有序性都应该怎么保证呢">20.原子性、可见性、有序性都应该怎么保证呢？</a></li>
<li><a href="#21-分析下面几行代码的原子性">21. 分析下面几行代码的原子性？</a></li>
<li><a href="#22那说说什么是指令重排">22.那说说什么是指令重排？</a></li>
<li><a href="#23as-if-serial又是什么单线程的程序一定是顺序的吗">23.as-if-serial又是什么？单线程的程序一定是顺序的吗？</a></li>
<li><a href="#24volatile实现原理了解吗">24.volatile实现原理了解吗？</a></li>
</ul>
</li>
<li><a href="#锁">锁</a>
<ul>
<li><a href="#25synchronized用过吗怎么使用">25.synchronized用过吗？怎么使用？</a></li>
<li><a href="#26synchronized的实现原理">26.synchronized的实现原理？</a></li>
<li><a href="#27synchronized怎么保证可见性">27.synchronized怎么保证可见性？</a></li>
<li><a href="#28synchronized怎么保证有序性">28.synchronized怎么保证有序性？</a></li>
<li><a href="#29synchronized怎么实现可重入的呢">29.synchronized怎么实现可重入的呢？</a></li>
<li><a href="#30锁升级synchronized优化了解吗">30.锁升级？synchronized优化了解吗？</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
</aside>
</header>
<article class="markdown"><h2 id="基础">
  基础
  <a class="anchor" href="#%e5%9f%ba%e7%a1%80">#</a>
</h2>
<h3 id="1并行跟并发有什么区别">
  1.并行跟并发有什么区别？
  <a class="anchor" href="#1%e5%b9%b6%e8%a1%8c%e8%b7%9f%e5%b9%b6%e5%8f%91%e6%9c%89%e4%bb%80%e4%b9%88%e5%8c%ba%e5%88%ab">#</a>
</h3>
<ul>
<li>并行就是同一时刻，两个线程都在执行。这就要求有两个CPU去分别执行两个线程。</li>
<li>并发就是同一时刻，只有一个执行，但是一个时间段内，两个线程都执行了。并发的实现依赖于CPU切换线程，因为切换的时间特别短，所以基本对于用户是无感知的。</li>
</ul>
<h3 id="2说说什么是进程和线程">
  2.说说什么是进程和线程？
  <a class="anchor" href="#2%e8%af%b4%e8%af%b4%e4%bb%80%e4%b9%88%e6%98%af%e8%bf%9b%e7%a8%8b%e5%92%8c%e7%ba%bf%e7%a8%8b">#</a>
</h3>
<ul>
<li>进程：进程是代码在数据集合上的一次运行活动，是系统进行资源分配和调度的基本单位。</li>
<li>线程：线程是进程的一个执行路径，一个进程中至少有一个线程，进程中的多个线程共享进程的资源。</li>
</ul>
<h3 id="3说说线程有几种创建方式">
  3.说说线程有几种创建方式？
  <a class="anchor" href="#3%e8%af%b4%e8%af%b4%e7%ba%bf%e7%a8%8b%e6%9c%89%e5%87%a0%e7%a7%8d%e5%88%9b%e5%bb%ba%e6%96%b9%e5%bc%8f">#</a>
</h3>
<p>Java中创建线程主要有三种方式，分别为继承Thread类、实现Runnable接口、实现Callable接口。</p>
<ul>
<li>
<p>继承Thread类，重写run()方法，调用start()方法启动线程</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ThreadTest</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">/**
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">     * 继承Thread类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">     */</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">MyThread</span> <span style="color:#66d9ef">extends</span> Thread <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">run</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"This is child thread"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        MyThread thread <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> MyThread<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        thread<span style="color:#f92672">.</span><span style="color:#a6e22e">start</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>实现 Runnable 接口，重写run()方法</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">RunnableTask</span> <span style="color:#66d9ef">implements</span> Runnable <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">run</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"Runnable!"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        RunnableTask task <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> RunnableTask<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">new</span> Thread<span style="color:#f92672">(</span>task<span style="color:#f92672">).</span><span style="color:#a6e22e">start</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>实现Callable接口，重写call()方法，这种方式可以通过FutureTask获取任务执行的返回值</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">CallerTask</span> <span style="color:#66d9ef">implements</span> Callable<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">&gt;</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">call</span><span style="color:#f92672">()</span> <span style="color:#66d9ef">throws</span> Exception <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">"Hello,i am running!"</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//创建异步任务
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        FutureTask<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">&gt;</span> task<span style="color:#f92672">=</span><span style="color:#66d9ef">new</span> FutureTask<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">&gt;(</span><span style="color:#66d9ef">new</span> CallerTask<span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//启动线程
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        <span style="color:#66d9ef">new</span> Thread<span style="color:#f92672">(</span>task<span style="color:#f92672">).</span><span style="color:#a6e22e">start</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">try</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#75715e">//等待执行完成，并获取返回结果
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>            String result<span style="color:#f92672">=</span>task<span style="color:#f92672">.</span><span style="color:#a6e22e">get</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>            System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span>result<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span> <span style="color:#66d9ef">catch</span> <span style="color:#f92672">(</span>InterruptedException e<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            e<span style="color:#f92672">.</span><span style="color:#a6e22e">printStackTrace</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span> <span style="color:#66d9ef">catch</span> <span style="color:#f92672">(</span>ExecutionException e<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            e<span style="color:#f92672">.</span><span style="color:#a6e22e">printStackTrace</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
</ul>
<h3 id="4为什么调用start方法时会执行run方法那怎么不直接调用run方法">
  4.为什么调用start()方法时会执行run()方法，那怎么不直接调用run()方法？
  <a class="anchor" href="#4%e4%b8%ba%e4%bb%80%e4%b9%88%e8%b0%83%e7%94%a8start%e6%96%b9%e6%b3%95%e6%97%b6%e4%bc%9a%e6%89%a7%e8%a1%8crun%e6%96%b9%e6%b3%95%e9%82%a3%e6%80%8e%e4%b9%88%e4%b8%8d%e7%9b%b4%e6%8e%a5%e8%b0%83%e7%94%a8run%e6%96%b9%e6%b3%95">#</a>
</h3>
<p>JVM执行start方法，会先创建一条线程，由创建出来的新线程去执行thread的run方法，这才起到多线程的效果。如果直接调用Thread的run()方法，那么run方法还是运行在主线程中，相当于顺序执行，就起不到多线程的效果。</p>
<h3 id="5线程有哪些常用的调度方法">
  5.线程有哪些常用的调度方法？
  <a class="anchor" href="#5%e7%ba%bf%e7%a8%8b%e6%9c%89%e5%93%aa%e4%ba%9b%e5%b8%b8%e7%94%a8%e7%9a%84%e8%b0%83%e5%ba%a6%e6%96%b9%e6%b3%95">#</a>
</h3>
<ul>
<li>等待：wait()、join()</li>
<li>通知：notify()、notifyAll()</li>
<li>让出优先权：yield()</li>
<li>中断： interrupt() 、isInterrupted()</li>
<li>休眠：sleep(long millis)</li>
</ul>
<h3 id="6线程有几种状态">
  6.线程有几种状态？
  <a class="anchor" href="#6%e7%ba%bf%e7%a8%8b%e6%9c%89%e5%87%a0%e7%a7%8d%e7%8a%b6%e6%80%81">#</a>
</h3>
<table>
<thead>
<tr>
<th>状态</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>NEW</td>
<td>初始状态：线程被创建，但还没有调用start()方法</td>
</tr>
<tr>
<td>RUNNABLE</td>
<td>运行状态：Java线程将操作系统中的就绪和运行两种状态笼统的称作“运行”</td>
</tr>
<tr>
<td>BLOCKED</td>
<td>阻塞状态：表示线程阻塞于锁</td>
</tr>
<tr>
<td>WAITING</td>
<td>等待状态：表示线程进入等待状态，进入该状态表示当前线程需要等待其他线程做出一些特定动作（通知或中断）</td>
</tr>
<tr>
<td>TIME_WAITING</td>
<td>超时等待状态：该状态不同于 WAITIND，它是可以在指定的时间自行返回的</td>
</tr>
<tr>
<td>TERMINATED</td>
<td>终止状态：表示当前线程已经执行完毕</td>
</tr>
</tbody>
</table>
<h3 id="7什么是线程上下文切换">
  7.什么是线程上下文切换？
  <a class="anchor" href="#7%e4%bb%80%e4%b9%88%e6%98%af%e7%ba%bf%e7%a8%8b%e4%b8%8a%e4%b8%8b%e6%96%87%e5%88%87%e6%8d%a2">#</a>
</h3>
<p>使用多线程的目的是为了充分利用CPU，但是我们知道，并发其实是一个CPU来应付多个线程。为了让用户感觉多个线程是在同时执行的， CPU 资源的分配采用了时间片轮转也就是给每个线程分配一个时间片，线程在时间片内占用 CPU 执行任务。</p>
<h3 id="8守护线程了解吗">
  8.守护线程了解吗？
  <a class="anchor" href="#8%e5%ae%88%e6%8a%a4%e7%ba%bf%e7%a8%8b%e4%ba%86%e8%a7%a3%e5%90%97">#</a>
</h3>
<p>Java中的线程分为两类，分别为 daemon 线程（守护线程）和 user 线程（用户线程）。如在JVM 启动时会调用 main 函数，main函数所在的线程就是一个用户线程。其实在 JVM 内部同时还启动了很多守护线程， 比如垃圾回收线程。</p>
<p>区别之一是当最后一个非守护线程束时， JVM会正常退出，而不管当前是否存在守护线程，也就是说守护线程是否结束并不影响 JVM退出。换而言之，只要有一个用户线程还没结束，正常情况下JVM就不会退出。</p>
<h3 id="9线程间有哪些通信方式">
  9.线程间有哪些通信方式？
  <a class="anchor" href="#9%e7%ba%bf%e7%a8%8b%e9%97%b4%e6%9c%89%e5%93%aa%e4%ba%9b%e9%80%9a%e4%bf%a1%e6%96%b9%e5%bc%8f">#</a>
</h3>
<ul>
<li>
<p>volatile和synchronized关键字</p>
</li>
<li>
<p>等待/通知机制</p>
</li>
<li>
<p>管道输入/输出流</p>
</li>
<li>
<p>使用Thread.join()</p>
</li>
<li>
<p>使用ThreadLocal</p>
</li>
</ul>
<h2 id="threadlocal">
  ThreadLocal
  <a class="anchor" href="#threadlocal">#</a>
</h2>
<h3 id="10threadlocal是什么">
  10.ThreadLocal是什么？
  <a class="anchor" href="#10threadlocal%e6%98%af%e4%bb%80%e4%b9%88">#</a>
</h3>
<p>ThreadLocal，也就是线程本地变量。如果你创建了一个ThreadLocal变量，那么访问这个变量的每个线程都会有这个变量的一个本地拷贝，多个线程操作这个变量的时候，实际是操作自己本地内存里面的变量，从而起到线程隔离的作用，避免了线程安全问题。</p>
<h3 id="11threadlocal怎么实现的呢">
  11.ThreadLocal怎么实现的呢？
  <a class="anchor" href="#11threadlocal%e6%80%8e%e4%b9%88%e5%ae%9e%e7%8e%b0%e7%9a%84%e5%91%a2">#</a>
</h3>
<ul>
<li>Thread类有一个类型为ThreadLocal.ThreadLocalMap的实例变量threadLocals，每个线程都有一个属于自己的ThreadLocalMap。</li>
<li>ThreadLocalMap内部维护着Entry数组，每个Entry代表一个完整的对象，key是ThreadLocal的弱引用，value是ThreadLocal的泛型值。</li>
<li>每个线程在往ThreadLocal里设置值的时候，都是往自己的ThreadLocalMap里存，读也是以某个ThreadLocal作为引用，在自己的map里找对应的key，从而实现了线程隔离。</li>
<li>ThreadLocal本身不存储值，它只是作为一个key来让线程往ThreadLocalMap里存取值。</li>
</ul>
<h3 id="12threadlocal-内存泄露是怎么回事">
  12.ThreadLocal 内存泄露是怎么回事？
  <a class="anchor" href="#12threadlocal-%e5%86%85%e5%ad%98%e6%b3%84%e9%9c%b2%e6%98%af%e6%80%8e%e4%b9%88%e5%9b%9e%e4%ba%8b">#</a>
</h3>
<p>ThreadLocalMap中使用的 key 为 ThreadLocal 的弱引用(只要垃圾回收机制一运行，不管JVM的内存空间是否充足，都会回收该对象占用的内存。)。弱引用很容易被回收，如果ThreadLocal（ThreadLocalMap的Key）被垃圾回收器回收了，但是ThreadLocalMap生命周期和Thread是一样的，它这时候如果不被回收，就会出现这种情况：ThreadLocalMap的key没了，value还在，这就会<strong>造成了内存泄漏问题</strong>。</p>
<h3 id="13怎么解决内存泄漏问题呢">
  13.怎么解决内存泄漏问题呢？
  <a class="anchor" href="#13%e6%80%8e%e4%b9%88%e8%a7%a3%e5%86%b3%e5%86%85%e5%ad%98%e6%b3%84%e6%bc%8f%e9%97%ae%e9%a2%98%e5%91%a2">#</a>
</h3>
<p>使用完ThreadLocal后，及时调用remove()方法释放内存空间。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span>ThreadLocal<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">&gt;</span> localVariable <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> ThreadLocal<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">try</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    localVariable<span style="color:#f92672">.</span><span style="color:#a6e22e">set</span><span style="color:#f92672">(</span><span style="color:#960050;background-color:#1e0010">"</span>鄙人三某<span style="color:#960050;background-color:#1e0010">”</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#960050;background-color:#1e0010">……</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span> <span style="color:#66d9ef">finally</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    localVariable<span style="color:#f92672">.</span><span style="color:#a6e22e">remove</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><h3 id="14threadlocalmap的结构了解吗">
  14.ThreadLocalMap的结构了解吗？
  <a class="anchor" href="#14threadlocalmap%e7%9a%84%e7%bb%93%e6%9e%84%e4%ba%86%e8%a7%a3%e5%90%97">#</a>
</h3>
<p>ThreadLocalMap虽然被叫做Map，其实它是没有实现Map接口的，但是结构还是和HashMap比较类似的，主要关注的是两个要素：<code>元素数组</code>和<code>散列方法</code>。</p>
<ul>
<li>
<p>元素数组</p>
<p>一个table数组，存储Entry类型的元素，Entry是ThreaLocal弱引用作为key，Object作为value的结构。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> Entry<span style="color:#f92672">[]</span> table<span style="color:#f92672">;</span>
</span></span></code></pre></div></li>
<li>
<p>散列方法</p>
<p>散列方法就是怎么把对应的key映射到table数组的相应下标，ThreadLocalMap用的是哈希取余法，取出key的threadLocalHashCode，然后和table数组长度减一&amp;运算（相当于取余）。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">int</span> i <span style="color:#f92672">=</span> key<span style="color:#f92672">.</span><span style="color:#a6e22e">threadLocalHashCode</span> <span style="color:#f92672">&amp;</span> <span style="color:#f92672">(</span>table<span style="color:#f92672">.</span><span style="color:#a6e22e">length</span> <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span><span style="color:#f92672">);</span>
</span></span></code></pre></div><p>这里的threadLocalHashCode计算有点东西，每创建一个ThreadLocal对象，它就会新增<code>0x61c88647</code>，这个值很特殊，它是<strong>斐波那契数</strong> 也叫 <strong>黄金分割数</strong>。<code>hash</code>增量为 这个数字，带来的好处就是 <code>hash</code> <strong>分布非常均匀</strong>。</p>
</li>
</ul>
<h3 id="15threadlocalmap怎么解决hash冲突的">
  15.ThreadLocalMap怎么解决Hash冲突的？
  <a class="anchor" href="#15threadlocalmap%e6%80%8e%e4%b9%88%e8%a7%a3%e5%86%b3hash%e5%86%b2%e7%aa%81%e7%9a%84">#</a>
</h3>
<p>都知道HashMap使用了链表来解决冲突，也就是所谓的链地址法。ThreadLocalMap没有使用链表，自然也不是用链地址法来解决冲突了，它用的是另外一种方式——<strong>开放定址法</strong>。开放定址法是什么意思呢？简单来说，就是这个坑被人占了，那就接着去找空着的坑。</p>
<h3 id="16threadlocalmap扩容机制了解吗">
  16.ThreadLocalMap扩容机制了解吗？
  <a class="anchor" href="#16threadlocalmap%e6%89%a9%e5%ae%b9%e6%9c%ba%e5%88%b6%e4%ba%86%e8%a7%a3%e5%90%97">#</a>
</h3>
<p>在ThreadLocalMap.set()方法的最后，如果执行完启发式清理工作后，未清理到任何数据，且当前散列数组中<code>Entry</code>的数量已经达到了列表的扩容阈值<code>(len*2/3)</code>，就开始执行<code>rehash()</code>逻辑：</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">(!</span>cleanSomeSlots<span style="color:#f92672">(</span>i<span style="color:#f92672">,</span> sz<span style="color:#f92672">)</span> <span style="color:#f92672">&amp;&amp;</span> sz <span style="color:#f92672">&gt;=</span> threshold<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    rehash<span style="color:#f92672">();</span>
</span></span></code></pre></div><p>再着看rehash()具体实现：这里会先去清理过期的Entry，然后还要根据条件判断<code>size &gt;= threshold - threshold / 4</code> 也就是<code>size &gt;= threshold* 3/4</code>来决定是否需要扩容。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">private</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">rehash</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//清理过期Entry
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    expungeStaleEntries<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//扩容
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>size <span style="color:#f92672">&gt;=</span> threshold <span style="color:#f92672">-</span> threshold <span style="color:#f92672">/</span> <span style="color:#ae81ff">4</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>        resize<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//清理过期Entry
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">private</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">expungeStaleEntries</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    Entry<span style="color:#f92672">[]</span> tab <span style="color:#f92672">=</span> table<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">int</span> len <span style="color:#f92672">=</span> tab<span style="color:#f92672">.</span><span style="color:#a6e22e">length</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">for</span> <span style="color:#f92672">(</span><span style="color:#66d9ef">int</span> j <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span><span style="color:#f92672">;</span> j <span style="color:#f92672">&lt;</span> len<span style="color:#f92672">;</span> j<span style="color:#f92672">++)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        Entry e <span style="color:#f92672">=</span> tab<span style="color:#f92672">[</span>j<span style="color:#f92672">];</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>e <span style="color:#f92672">!=</span> <span style="color:#66d9ef">null</span> <span style="color:#f92672">&amp;&amp;</span> e<span style="color:#f92672">.</span><span style="color:#a6e22e">get</span><span style="color:#f92672">()</span> <span style="color:#f92672">==</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>            expungeStaleEntry<span style="color:#f92672">(</span>j<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><p>接着看看具体的<code>resize()</code>方法，扩容后的<code>newTab</code>的大小为老数组的两倍，然后遍历老的table数组，散列方法重新计算位置，开放地址解决冲突，然后放到新的<code>newTab</code>，遍历完成之后，<code>oldTab</code>中所有的<code>entry</code>数据都已经放入到<code>newTab</code>中了，然后table引用指向<code>newTab</code></p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">// 扩容规则:双倍扩容
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">private</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">resize</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>	Entry<span style="color:#f92672">[]</span> oldTab <span style="color:#f92672">=</span> table<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">int</span> oldLen <span style="color:#f92672">=</span> oldTab<span style="color:#f92672">.</span><span style="color:#a6e22e">length</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">int</span> newLen <span style="color:#f92672">=</span> oldLen <span style="color:#f92672">*</span> <span style="color:#ae81ff">2</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>	Entry<span style="color:#f92672">[]</span> newTab <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Entry<span style="color:#f92672">[</span>newLen<span style="color:#f92672">];</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">int</span> count <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">for</span> <span style="color:#f92672">(</span><span style="color:#66d9ef">int</span> j <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span><span style="color:#f92672">;</span> j <span style="color:#f92672">&lt;</span> oldLen<span style="color:#f92672">;</span> <span style="color:#f92672">++</span>j<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>		Entry e <span style="color:#f92672">=</span> oldTab<span style="color:#f92672">[</span>j<span style="color:#f92672">];</span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>e <span style="color:#f92672">!=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>			ThreadLocal<span style="color:#f92672">&lt;?&gt;</span> k <span style="color:#f92672">=</span> e<span style="color:#f92672">.</span><span style="color:#a6e22e">get</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>k <span style="color:#f92672">==</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>				<span style="color:#75715e">// 扩容期间发现过期元素，会跳过
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>				e<span style="color:#f92672">.</span><span style="color:#a6e22e">value</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">;</span> <span style="color:#75715e">// Help the GC
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>			<span style="color:#f92672">}</span> <span style="color:#66d9ef">else</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>				<span style="color:#75715e">// 将旧数组中没有过期的元素挪到新数组里
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>				<span style="color:#66d9ef">int</span> h <span style="color:#f92672">=</span> k<span style="color:#f92672">.</span><span style="color:#a6e22e">threadLocalHashCode</span> <span style="color:#f92672">&amp;</span> <span style="color:#f92672">(</span>newLen <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>				<span style="color:#66d9ef">while</span> <span style="color:#f92672">(</span>newTab<span style="color:#f92672">[</span>h<span style="color:#f92672">]</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>					h <span style="color:#f92672">=</span> nextIndex<span style="color:#f92672">(</span>h<span style="color:#f92672">,</span> newLen<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>				newTab<span style="color:#f92672">[</span>h<span style="color:#f92672">]</span> <span style="color:#f92672">=</span> e<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>				count<span style="color:#f92672">++;</span>
</span></span><span style="display:flex;"><span>			<span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>		<span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">// 重新设置阈值
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>	setThreshold<span style="color:#f92672">(</span>newLen<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>	size <span style="color:#f92672">=</span> count<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>	table <span style="color:#f92672">=</span> newTab<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><h3 id="17父子线程怎么共享数据">
  17.父子线程怎么共享数据？
  <a class="anchor" href="#17%e7%88%b6%e5%ad%90%e7%ba%bf%e7%a8%8b%e6%80%8e%e4%b9%88%e5%85%b1%e4%ba%ab%e6%95%b0%e6%8d%ae">#</a>
</h3>
<p>在主线程的InheritableThreadLocal实例设置值，在子线程中就可以拿到了。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">InheritableThreadLocalTest</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">final</span> ThreadLocal threadLocal <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> InheritableThreadLocal<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// 主线程
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        threadLocal<span style="color:#f92672">.</span><span style="color:#a6e22e">set</span><span style="color:#f92672">(</span><span style="color:#e6db74">"不擅技术"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//子线程
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Thread t <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Thread<span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">run</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">super</span><span style="color:#f92672">.</span><span style="color:#a6e22e">run</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>                System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"鄙人三某 ，"</span> <span style="color:#f92672">+</span> threadLocal<span style="color:#f92672">.</span><span style="color:#a6e22e">get</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">};</span>
</span></span><span style="display:flex;"><span>        t<span style="color:#f92672">.</span><span style="color:#a6e22e">start</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><p>原理很简单，在Thread类里还有另外一个变量：</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span>ThreadLocal<span style="color:#f92672">.</span><span style="color:#a6e22e">ThreadLocalMap</span> inheritableThreadLocals <span style="color:#f92672">=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">;</span>
</span></span></code></pre></div><p>在Thread.init的时候，如果父线程的<code>inheritableThreadLocals</code>不为空，就把它赋给当前线程（子线程）的<code>inheritableThreadLocals </code>。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>inheritThreadLocals <span style="color:#f92672">&amp;&amp;</span> parent<span style="color:#f92672">.</span><span style="color:#a6e22e">inheritableThreadLocals</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">inheritableThreadLocals</span> <span style="color:#f92672">=</span>
</span></span><span style="display:flex;"><span>        ThreadLocal<span style="color:#f92672">.</span><span style="color:#a6e22e">createInheritedMap</span><span style="color:#f92672">(</span>parent<span style="color:#f92672">.</span><span style="color:#a6e22e">inheritableThreadLocals</span><span style="color:#f92672">);</span>
</span></span></code></pre></div><h2 id="java内存模型">
  Java内存模型
  <a class="anchor" href="#java%e5%86%85%e5%ad%98%e6%a8%a1%e5%9e%8b">#</a>
</h2>
<h3 id="18说一下你对java内存模型jmm的理解">
  18.说一下你对Java内存模型（JMM）的理解？
  <a class="anchor" href="#18%e8%af%b4%e4%b8%80%e4%b8%8b%e4%bd%a0%e5%af%b9java%e5%86%85%e5%ad%98%e6%a8%a1%e5%9e%8bjmm%e7%9a%84%e7%90%86%e8%a7%a3">#</a>
</h3>
<p>Java内存模型（Java Memory Model，JMM），是一种抽象的模型，被定义出来屏蔽各种硬件和操作系统的内存访问差异。</p>
<p>JMM定义了线程和主内存之间的抽象关系：线程之间的共享变量存储在<code>主内存</code>（Main Memory）中，每个线程都有一个私有的<code>本地内存</code>（Local Memory），本地内存中存储了该线程以读/写共享变量的副本。</p>
<h3 id="19说说你对原子性可见性有序性的理解">
  19.说说你对原子性、可见性、有序性的理解？
  <a class="anchor" href="#19%e8%af%b4%e8%af%b4%e4%bd%a0%e5%af%b9%e5%8e%9f%e5%ad%90%e6%80%a7%e5%8f%af%e8%a7%81%e6%80%a7%e6%9c%89%e5%ba%8f%e6%80%a7%e7%9a%84%e7%90%86%e8%a7%a3">#</a>
</h3>
<p>原子性、有序性、可见性是并发编程中非常重要的基础概念，JMM的很多技术都是围绕着这三大特性展开。</p>
<ul>
<li><strong>原子性</strong>：原子性指的是一个操作是不可分割、不可中断的，要么全部执行并且执行的过程不会被任何因素打断，要么就全不执行。</li>
<li><strong>可见性</strong>：可见性指的是一个线程修改了某一个共享变量的值时，其它线程能够立即知道这个修改。</li>
<li><strong>有序性</strong>：有序性指的是对于一个线程的执行代码，从前往后依次执行，单线程下可以认为程序是有序的，但是并发时有可能会发生指令重排。</li>
</ul>
<h3 id="20原子性可见性有序性都应该怎么保证呢">
  20.原子性、可见性、有序性都应该怎么保证呢？
  <a class="anchor" href="#20%e5%8e%9f%e5%ad%90%e6%80%a7%e5%8f%af%e8%a7%81%e6%80%a7%e6%9c%89%e5%ba%8f%e6%80%a7%e9%83%bd%e5%ba%94%e8%af%a5%e6%80%8e%e4%b9%88%e4%bf%9d%e8%af%81%e5%91%a2">#</a>
</h3>
<ul>
<li>原子性：JMM只能保证基本的原子性，如果要保证一个代码块的原子性，需要使用<code>synchronized </code>。</li>
<li>可见性：Java是利用<code>volatile</code>关键字来保证可见性的，除此之外，<code>final</code>和<code>synchronized</code>也能保证可见性。</li>
<li>有序性：<code>synchronized</code>或者<code>volatile</code>都可以保证多线程之间操作的有序性。</li>
</ul>
<h3 id="21-分析下面几行代码的原子性">
  21. 分析下面几行代码的原子性？
  <a class="anchor" href="#21-%e5%88%86%e6%9e%90%e4%b8%8b%e9%9d%a2%e5%87%a0%e8%a1%8c%e4%bb%a3%e7%a0%81%e7%9a%84%e5%8e%9f%e5%ad%90%e6%80%a7">#</a>
</h3>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">int</span> i <span style="color:#f92672">=</span> <span style="color:#ae81ff">2</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">int</span> j <span style="color:#f92672">=</span> i<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>i<span style="color:#f92672">++;</span>
</span></span><span style="display:flex;"><span>i <span style="color:#f92672">=</span> i <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span><span style="color:#f92672">;</span>
</span></span></code></pre></div><ul>
<li>第1句是基本类型赋值，是原子性操作。</li>
<li>第2句先读i的值，再赋值到j，两步操作，不能保证原子性。</li>
<li>第3和第4句其实是等效的，先读取i的值，再+1，最后赋值到i，三步操作了，不能保证原子性。</li>
</ul>
<h3 id="22那说说什么是指令重排">
  22.那说说什么是指令重排？
  <a class="anchor" href="#22%e9%82%a3%e8%af%b4%e8%af%b4%e4%bb%80%e4%b9%88%e6%98%af%e6%8c%87%e4%bb%a4%e9%87%8d%e6%8e%92">#</a>
</h3>
<p>在执行程序时，为了提高性能，编译器和处理器常常会对指令做重排序。重排序分3种类型。</p>
<ol>
<li>编译器优化的重排序。编译器在不改变单线程程序语义的前提下，可以重新安排语句的执行顺序。</li>
<li>指令级并行的重排序。现代处理器采用了指令级并行技术（Instruction-Level Parallelism，ILP）来将多条指令重叠执行。如果不存在数据依赖性，处理器可以改变语句对应 机器指令的执行顺序。</li>
<li>内存系统的重排序。由于处理器使用缓存和读/写缓冲区，这使得加载和存储操作看上去可能是在乱序执行。</li>
</ol>
<h3 id="23as-if-serial又是什么单线程的程序一定是顺序的吗">
  23.as-if-serial又是什么？单线程的程序一定是顺序的吗？
  <a class="anchor" href="#23as-if-serial%e5%8f%88%e6%98%af%e4%bb%80%e4%b9%88%e5%8d%95%e7%ba%bf%e7%a8%8b%e7%9a%84%e7%a8%8b%e5%ba%8f%e4%b8%80%e5%ae%9a%e6%98%af%e9%a1%ba%e5%ba%8f%e7%9a%84%e5%90%97">#</a>
</h3>
<p>as-if-serial语义的意思是：不管怎么重排序（编译器和处理器为了提高并行度），<strong>单线程程序的执行结果不能被改变</strong>。编译器、runtime和处理器都必须遵守as-if-serial语义。</p>
<h3 id="24volatile实现原理了解吗">
  24.volatile实现原理了解吗？
  <a class="anchor" href="#24volatile%e5%ae%9e%e7%8e%b0%e5%8e%9f%e7%90%86%e4%ba%86%e8%a7%a3%e5%90%97">#</a>
</h3>
<p>volatile有两个作用，保证<strong>可见性</strong>和<strong>有序性</strong>。</p>
<p>volatile可以确保对某个变量的更新对其他线程马上可见，一个变量被声明为volatile 时，线程在写入变量时不会把值缓存在寄存器或者其他地方，而是会把值刷新回主内存 当其它线程读取该共享变量 ，会从主内存重新获取最新值，而不是使用当前线程的本地内存中的值。</p>
<p>相比synchronized的加锁方式来解决共享变量的内存可见性问题，volatile就是更轻量的选择，它没有上下文切换的额外开销成本。</p>
<h2 id="锁">
  锁
  <a class="anchor" href="#%e9%94%81">#</a>
</h2>
<h3 id="25synchronized用过吗怎么使用">
  25.synchronized用过吗？怎么使用？
  <a class="anchor" href="#25synchronized%e7%94%a8%e8%bf%87%e5%90%97%e6%80%8e%e4%b9%88%e4%bd%bf%e7%94%a8">#</a>
</h3>
<p>synchronized经常用的，用来保证代码的原子性。synchronized主要有三种用法：</p>
<ul>
<li>修饰实例方法：作用于当前对象实例加锁，锁方法的调用者，谁先拿到锁谁先执行，普通方法不受限制</li>
<li>修饰静态方法：作用于当前类加锁，类一加载就有了，锁的是当前类，任何对象实例谁先拿到锁谁先执行</li>
<li>修饰代码块 ：指定加锁对象，对给定对象/类加锁。</li>
</ul>
<h3 id="26synchronized的实现原理">
  26.synchronized的实现原理？
  <a class="anchor" href="#26synchronized%e7%9a%84%e5%ae%9e%e7%8e%b0%e5%8e%9f%e7%90%86">#</a>
</h3>
<ol>
<li>synchronized修饰代码块时，JVM采用<code>monitorenter</code>、<code>monitorexit</code>两个指令来实现同步，<code>monitorenter</code> 指令指向同步代码块的开始位置， <code>monitorexit</code> 指令则指向同步代码块的结束位置。</li>
<li>synchronized修饰同步方法时，JVM采用<code>ACC_SYNCHRONIZED</code>标记符来实现同步，这个标识指明了该方法是一个同步方法。</li>
</ol>
<h3 id="27synchronized怎么保证可见性">
  27.synchronized怎么保证可见性？
  <a class="anchor" href="#27synchronized%e6%80%8e%e4%b9%88%e4%bf%9d%e8%af%81%e5%8f%af%e8%a7%81%e6%80%a7">#</a>
</h3>
<ul>
<li>线程加锁前，将清空工作内存中共享变量的值，从而使用共享变量时需要从主内存中重新读取最新的值。</li>
<li>线程加锁后，其它线程无法获取主内存中的共享变量。</li>
<li>线程解锁前，必须把共享变量的最新值刷新到主内存中。</li>
</ul>
<h3 id="28synchronized怎么保证有序性">
  28.synchronized怎么保证有序性？
  <a class="anchor" href="#28synchronized%e6%80%8e%e4%b9%88%e4%bf%9d%e8%af%81%e6%9c%89%e5%ba%8f%e6%80%a7">#</a>
</h3>
<p>synchronized同步的代码块，具有排他性，一次只能被一个线程拥有，所以synchronized保证同一时刻，代码是单线程执行的。因为as-if-serial语义的存在，单线程的程序能保证最终结果是有序的，但是不保证不会指令重排。</p>
<p>所以synchronized保证的有序是执行结果的有序性，而不是防止指令重排的有序性。</p>
<h3 id="29synchronized怎么实现可重入的呢">
  29.synchronized怎么实现可重入的呢？
  <a class="anchor" href="#29synchronized%e6%80%8e%e4%b9%88%e5%ae%9e%e7%8e%b0%e5%8f%af%e9%87%8d%e5%85%a5%e7%9a%84%e5%91%a2">#</a>
</h3>
<p>synchronized 是可重入锁，也就是说，允许一个线程二次请求自己持有对象锁的临界资源，这种情况称为可重入锁。</p>
<p>synchronized 锁对象的时候有个计数器，他会记录下线程获取锁的次数，在执行完对应的代码块之后，计数器就会-1，直到计数器清零，就释放锁了。</p>
<p>之所以，是可重入的。是因为 synchronized 锁对象有个计数器，会随着线程获取锁后 +1 计数，当线程执行完毕后 -1，直到清零释放锁。</p>
<h3 id="30锁升级synchronized优化了解吗">
  30.锁升级？synchronized优化了解吗？
  <a class="anchor" href="#30%e9%94%81%e5%8d%87%e7%ba%a7synchronized%e4%bc%98%e5%8c%96%e4%ba%86%e8%a7%a3%e5%90%97">#</a>
</h3>
<p>Java对象头里，有一块结构，叫<code>Mark Word</code>标记字段，这块结构会随着锁的状态变化而变化。</p>
</article>
<footer class="book-footer">
<div class="flex flex-wrap justify-between">
</div>
<script>(function(){function e(e){const t=window.getSelection(),n=document.createRange();n.selectNodeContents(e),t.removeAllRanges(),t.addRange(n)}document.querySelectorAll("pre code").forEach(t=>{t.addEventListener("click",function(){if(window.getSelection().toString())return;e(t.parentElement),navigator.clipboard&&navigator.clipboard.writeText(t.parentElement.textContent)})})})()</script>
</footer>
<div class="book-comments">
</div>
<label class="hidden book-menu-overlay" for="menu-control"></label>
</div>
<aside class="book-toc">
<div class="book-toc-content">
<nav id="TableOfContents">
<ul>
<li>
<ul>
<li><a href="#基础">基础</a>
<ul>
<li><a href="#1并行跟并发有什么区别">1.并行跟并发有什么区别？</a></li>
<li><a href="#2说说什么是进程和线程">2.说说什么是进程和线程？</a></li>
<li><a href="#3说说线程有几种创建方式">3.说说线程有几种创建方式？</a></li>
<li><a href="#4为什么调用start方法时会执行run方法那怎么不直接调用run方法">4.为什么调用start()方法时会执行run()方法，那怎么不直接调用run()方法？</a></li>
<li><a href="#5线程有哪些常用的调度方法">5.线程有哪些常用的调度方法？</a></li>
<li><a href="#6线程有几种状态">6.线程有几种状态？</a></li>
<li><a href="#7什么是线程上下文切换">7.什么是线程上下文切换？</a></li>
<li><a href="#8守护线程了解吗">8.守护线程了解吗？</a></li>
<li><a href="#9线程间有哪些通信方式">9.线程间有哪些通信方式？</a></li>
</ul>
</li>
<li><a href="#threadlocal">ThreadLocal</a>
<ul>
<li><a href="#10threadlocal是什么">10.ThreadLocal是什么？</a></li>
<li><a href="#11threadlocal怎么实现的呢">11.ThreadLocal怎么实现的呢？</a></li>
<li><a href="#12threadlocal-内存泄露是怎么回事">12.ThreadLocal 内存泄露是怎么回事？</a></li>
<li><a href="#13怎么解决内存泄漏问题呢">13.怎么解决内存泄漏问题呢？</a></li>
<li><a href="#14threadlocalmap的结构了解吗">14.ThreadLocalMap的结构了解吗？</a></li>
<li><a href="#15threadlocalmap怎么解决hash冲突的">15.ThreadLocalMap怎么解决Hash冲突的？</a></li>
<li><a href="#16threadlocalmap扩容机制了解吗">16.ThreadLocalMap扩容机制了解吗？</a></li>
<li><a href="#17父子线程怎么共享数据">17.父子线程怎么共享数据？</a></li>
</ul>
</li>
<li><a href="#java内存模型">Java内存模型</a>
<ul>
<li><a href="#18说一下你对java内存模型jmm的理解">18.说一下你对Java内存模型（JMM）的理解？</a></li>
<li><a href="#19说说你对原子性可见性有序性的理解">19.说说你对原子性、可见性、有序性的理解？</a></li>
<li><a href="#20原子性可见性有序性都应该怎么保证呢">20.原子性、可见性、有序性都应该怎么保证呢？</a></li>
<li><a href="#21-分析下面几行代码的原子性">21. 分析下面几行代码的原子性？</a></li>
<li><a href="#22那说说什么是指令重排">22.那说说什么是指令重排？</a></li>
<li><a href="#23as-if-serial又是什么单线程的程序一定是顺序的吗">23.as-if-serial又是什么？单线程的程序一定是顺序的吗？</a></li>
<li><a href="#24volatile实现原理了解吗">24.volatile实现原理了解吗？</a></li>
</ul>
</li>
<li><a href="#锁">锁</a>
<ul>
<li><a href="#25synchronized用过吗怎么使用">25.synchronized用过吗？怎么使用？</a></li>
<li><a href="#26synchronized的实现原理">26.synchronized的实现原理？</a></li>
<li><a href="#27synchronized怎么保证可见性">27.synchronized怎么保证可见性？</a></li>
<li><a href="#28synchronized怎么保证有序性">28.synchronized怎么保证有序性？</a></li>
<li><a href="#29synchronized怎么实现可重入的呢">29.synchronized怎么实现可重入的呢？</a></li>
<li><a href="#30锁升级synchronized优化了解吗">30.锁升级？synchronized优化了解吗？</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
</div>
</aside>
</main>
</body>
</html>
